/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ejb.sessions;

import ejb.entities.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import models.*;

/**
 *
 * @author simone
 */
@Stateless
public class TDSession implements TDSessionRemote {

    @PersistenceContext(unitName = "TDEnterpriseApp-ejbPU")
    private EntityManager eMan;

    //login logout session
    @Override
    public UserDTO login(String name, String psw) {
        String psw_md5 = this.generateMD5(psw);
        boolean isEmployee;
        UserDTO user;
        String n;
        if (psw_md5 == null) {
            return null;
        }

        List<Cliente> clientList = eMan.createNamedQuery("Cliente.findByNameAndPassword", Cliente.class)
                .setParameter("name", name)
                .setParameter("psw", psw_md5)
                .getResultList();

        if (!clientList.isEmpty()) {
            n = clientList.get(0).getName();
            isEmployee = false;
            user = new UserDTO(n, isEmployee);
            user.setIdUtente(clientList.get(0).getIdCliente());
            return user;
        }

        List<Dipendente> dipList = eMan.createNamedQuery("Dipendente.findByNameAndPassword", Dipendente.class)
                .setParameter("name", name)
                .setParameter("psw", psw_md5)
                .getResultList();

        if (!dipList.isEmpty()) {
            n = dipList.get(0).getName();
            isEmployee = true;
            user = new UserDTO(n, isEmployee);
            user.setIdUtente(dipList.get(0).getIdDipendente());
            return user;
        }

        return null;
    }

    @Override
    public boolean register(String name, String psw, String email) {

        String psw_md5 = this.generateMD5(psw);
        if (psw_md5 == null) {
            return false;
        }

        List<Cliente> clientList = eMan.createNamedQuery("Cliente.findByEmail", Cliente.class)
                .setParameter("name", name)
                .setParameter("psw", psw_md5)
                .setParameter("email", email)
                .getResultList();
        if (!clientList.isEmpty()) {
            return false;
        }

        eMan.persist(new Cliente(name, psw_md5, email));

        return true;
    }

    private String generateMD5(String psw) {
        String psw_md5 = null;
        MessageDigest m;
        try {
            m = MessageDigest.getInstance("MD5");
            m.reset();
            m.update(psw.getBytes());
            byte[] digest = m.digest();
            psw_md5 = new BigInteger(1, digest).toString(16);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(TDSession.class.getName()).log(Level.SEVERE, null, ex);
        }
        return psw_md5;
    }

    // create packet session
    @Override
    public boolean createPacket(PacchettoDTO packetDTO) {
        ArrayList<hotelDTO> selectedHotel = packetDTO.getSelectedHotels();
        ArrayList<tourDTO> selectedTour = packetDTO.getSelectedTours();
        ArrayList<TripDTO> selectedTrip = packetDTO.getSelectedTrip();

        Pacchetto pack = new Pacchetto();
        pack.setName(packetDTO.getName());
        pack.setDescription(packetDTO.getDescription());
        pack.setOnSale(packetDTO.getOnSale());
        pack.setPredefinito(packetDTO.getPredef());
        pack.setDal(packetDTO.getDal());
        pack.setAl(packetDTO.getal());

        Tipostanza room = eMan.find(Tipostanza.class, packetDTO.getRoom().getIdStanza());

        pack.setFkStanza(room);
        for (hotelDTO hDTO : selectedHotel) {

            int index = hDTO.getIdHotel();
            Hotel h = eMan.find(Hotel.class, index);
            pack.getHotelsBelongTo().add(h);
        }

        for (tourDTO tDTO : selectedTour) {

            int index = tDTO.getIdTour();
            Escursione t = eMan.find(Escursione.class, index);
            pack.getToursBelongTo().add(t);
        }

        for (TripDTO trDTO : selectedTrip) {

            int index = trDTO.getIdTrip();
            Viaggio v = eMan.find(Viaggio.class, index);
            pack.getTripBelongsTo().add(v);
        }
        eMan.persist(pack);

        return true;
    }

    @Override
    public boolean createHotel(hotelDTO hDTO) {
        Hotel h = new Hotel();
        h.setAddress(hDTO.getAddress());
        h.setName(hDTO.getHotelName());
        h.setDescription(hDTO.getDescr());
        h.setRating(hDTO.getRating());

        Object cObj = hDTO.getCost();
        double costValue;
        if (cObj.getClass().toString().equals("class java.lang.Double")) {
            Double value = (Double) cObj;
            costValue = value.doubleValue();
        } else {
            Long value = (Long) cObj;
            costValue = value.doubleValue();
        }

        h.setCost(costValue);
        Citta city = eMan.find(Citta.class, hDTO.getCityHotel().getIdCity());
        h.setFkCitta(city);

        eMan.persist(h);

        return true;
    }

    @Override
    public boolean createTrip(TripDTO trDTO) {

        Viaggio v = new Viaggio();
        Citta cityArr = eMan.find(Citta.class,trDTO.getCittaArr().getIdCity());
        v.setFkArrivo(cityArr);
        
        Citta cityDep = eMan.find(Citta.class,trDTO.getCittaDep().getIdCity());
        v.setFkPartenza(cityDep);
        
        Object cObj = trDTO.getCost();
        double costValue;
        if (cObj.getClass().toString().equals("class java.lang.Double")) {
            Double value = (Double) cObj;
            costValue = value.doubleValue();
        } else {
            Long value = (Long) cObj;
            costValue = value.doubleValue();
        }
        v.setCost(costValue);
        Tipoviaggio tviaggio = eMan.find(Tipoviaggio.class, trDTO.gettWay().getIdTWay());
        v.setFkTipoViaggio(tviaggio);
        
        eMan.persist(v);

        return true;

    }

    @Override
    public boolean createTour(tourDTO tDTO) {
        Escursione e = new Escursione();
        e.setDescription(tDTO.getTourDescription());
        e.setName(tDTO.getNameTour());
        Citta city = eMan.find(Citta.class,tDTO.getCity().getIdCity());

        e.setFkCitta(city);

        Object cObj = tDTO.getCost();
        double costValue;
        if (cObj.getClass().toString().equals("class java.lang.Double")) {
            Double value = (Double) cObj;
            costValue = value.doubleValue();
        } else {
            Long value = (Long) cObj;
            costValue = value.doubleValue();
        }

        e.setCost(costValue);

        eMan.persist(e);

        return true;
    }

    @Override
    public boolean bookPacket(PrenotatoDTO ppDTO) {

        Pacchettoprenotato prenotato = new Pacchettoprenotato();
        prenotato.setDateAl(ppDTO.getAl());
        prenotato.setDateDal(ppDTO.getDal());
        prenotato.setNumPeople(ppDTO.getNum_persone());
        Pacchetto p = eMan.find(Pacchetto.class, ppDTO.getPacket().getIdPacchetto());

        if (ppDTO.getHotel() != null) {

            Hotel h = eMan.find(Hotel.class, ppDTO.getHotel().getIdHotel());
            prenotato.setFkHotel(h);
        }
        if (ppDTO.getTrip() != null) {

            Viaggio v = eMan.find(Viaggio.class, ppDTO.getTrip().getIdTrip());
            prenotato.setFkViaggio(v);
        }
        if (ppDTO.getTour() != null) {

            Escursione e = eMan.find(Escursione.class, ppDTO.getTour().getIdTour());
            prenotato.setFkEscursione(e);

        }
        Cliente c = eMan.find(Cliente.class, ppDTO.getUser().getIdUtente());

        prenotato.setFkPacchetto(p);
        prenotato.setFkCliente(c);
        eMan.persist(prenotato);
        return true;
    }

    @Override
    public ArrayList<PrenotatoDTO> getBookedPacket(UserDTO user) {
        List<Pacchettoprenotato> bookedPack = eMan.createNamedQuery("Pacchettoprenotato.findByUser", Pacchettoprenotato.class)
                .setParameter("idCliente", user.getIdUtente())
                .getResultList();

        ArrayList<PrenotatoDTO> bookedArray = new ArrayList<>();
        PrenotatoDTO booked;
        for (Pacchettoprenotato pP : bookedPack) {
            booked = new PrenotatoDTO();
            booked.setAl(pP.getDateAl());
            booked.setDal(pP.getDateDal());
            booked.setNum_persone(pP.getNumPeople());
            booked.setUser(user);
            booked.setHotel(hotelInBooking(pP));
            booked.setTour(tourInBooking(pP));
            booked.setTrip(tripInBooking(pP));
            booked.setPacket(setPacchettoDTO(pP.getFkPacchetto()));
            bookedArray.add(booked);
        }

        return bookedArray;
    }

    @Override
    public boolean updatePacket(PacchettoDTO packetDTO) {
        
        ArrayList<hotelDTO> selectedHotel = packetDTO.getSelectedHotels();
        ArrayList<tourDTO> selectedTour = packetDTO.getSelectedTours();
        ArrayList<TripDTO> selectedTrip = packetDTO.getSelectedTrip();


        List<Pacchettoprenotato> pPlist = eMan.createNamedQuery("Pacchettoprenotato.findPacchetto",Pacchettoprenotato.class)
                .setParameter("idPacchetto", packetDTO.getIdPacchetto())
                .getResultList();
        
        Pacchetto p = eMan.find(Pacchetto.class, packetDTO.getIdPacchetto());
        if(!pPlist.isEmpty() || p.getOnSale()==1)
            return false;
        
        Tipostanza room = eMan.find(Tipostanza.class, packetDTO.getRoom().getIdStanza());

        p.setOnSale(packetDTO.getOnSale());
        p.setPredefinito(packetDTO.getPredef());
        p.setDescription(packetDTO.getDescription());
        p.setName(packetDTO.getName());
        p.setDal(packetDTO.getDal());
        p.setAl(packetDTO.getal());
        p.setFkStanza(room);
        
        p.getHotelsBelongTo().clear(); 
        p.getToursBelongTo().clear();
        p.getTripBelongsTo().clear();
        eMan.merge(p);

        for (hotelDTO hDTO : selectedHotel) {

            int index = hDTO.getIdHotel();
            Hotel h = eMan.find(Hotel.class, index);
            p.getHotelsBelongTo().add(h);
        }

        for (tourDTO tDTO : selectedTour) {

            int index = tDTO.getIdTour();
            Escursione t = eMan.find(Escursione.class, index);
            p.getToursBelongTo().add(t);
        }

        for (TripDTO trDTO : selectedTrip) {

            int index = trDTO.getIdTrip();
            Viaggio v = eMan.find(Viaggio.class, index);
            p.getTripBelongsTo().add(v);
        }
        eMan.merge(p);
        return true;
    }

    private hotelDTO hotelInBooking(Pacchettoprenotato pP) {
        hotelDTO hotel = new hotelDTO();
        Hotel h = pP.getFkHotel();
        Object costObj;

        if (h == null) {
            return null;
        }

        hotel.setNameHotel(h.getName());
        hotel.setAddress(h.getAddress());
        hotel.setDescr(h.getDescription());
        hotel.setRating(h.getRating());
        costObj = Double.valueOf(h.getCost());
        hotel.setCost(costObj);
        hotel.setCityHotel(setCityDTO(h.getFkCitta()));
        return hotel;
    }

    private tourDTO tourInBooking(Pacchettoprenotato pP) {
        tourDTO tour = new tourDTO();
        Escursione e = pP.getFkEscursione();
        Object costObj;

        if (e == null) {
            return null;
        }

        costObj = Double.valueOf(e.getCost());
        tour.setCost(costObj);
        tour.setNameTour(e.getName());
        tour.setIdTour(e.getIdEscursioni());
        tour.setCity(setCityDTO(e.getFkCitta()));
        tour.setTourDescription(e.getDescription());

        return tour;

    }

    private TripDTO tripInBooking(Pacchettoprenotato pP) {
        TripDTO trip = new TripDTO();
        Viaggio v = pP.getFkViaggio();
        Object costObj;

        if (v == null) {
            return null;
        }

        costObj = Double.valueOf(v.getCost());
        trip.setCost(costObj);
        trip.settWay(setTwayDTO(v.getFkTipoViaggio()));
        trip.setIdTrip(v.getIdViaggio());
        trip.setCittaArr(setCityDTO(v.getFkArrivo()));
        trip.setCittaDep(setCityDTO(v.getFkPartenza()));
        trip.setName(v.getFkArrivo().getCity() + " " + v.getFkPartenza().getCity() + " - " + v.getFkTipoViaggio().getName());

        return trip;
    }

    @Override
    public ArrayList<hotelDTO> getAllHotels() {
        List<Hotel> hotelList = eMan.createNamedQuery("Hotel.findAll", Hotel.class)
                .getResultList();
        if (hotelList.isEmpty()) {
            return null;
        }
        hotelDTO hDTO;
        Object costObj = null;
        ArrayList<hotelDTO> hotelArray = new ArrayList<>();
        for (Hotel h : hotelList) {
            hDTO = setHotelDTO(h, costObj);
            hotelArray.add(hDTO);

        }
        return hotelArray;
    }

    @Override
    public ArrayList<stanzaDTO> getAllRooms() {
        List<Tipostanza> roomList = eMan.createNamedQuery("Tipostanza.findAll", Tipostanza.class)
                .getResultList();

        if (roomList.isEmpty()) {
            return null;
        }

        ArrayList<stanzaDTO> roomArray = new ArrayList<>();
        for (Tipostanza s : roomList) {
            roomArray.add(new stanzaDTO(s.getName(), s.getIdStanza()));
        }

        return roomArray;
    }

    @Override
    public ArrayList<TravelWayDTO> getAllTravelType() {
        List<Tipoviaggio> tWayList = eMan.createNamedQuery("Tipoviaggio.findAll", Tipoviaggio.class)
                .getResultList();

        if (tWayList.isEmpty()) {
            return null;
        }

        ArrayList<TravelWayDTO> tWayArray = new ArrayList<>();
        for (Tipoviaggio tv : tWayList) {
            tWayArray.add(new TravelWayDTO(tv.getName(), tv.getIdTipoViaggio()));
        }

        return tWayArray;
    }

    @Override
    public ArrayList<tourDTO> getAllTour() {
        List<Escursione> tourList = eMan.createNamedQuery("Escursione.findAll", Escursione.class)
                .getResultList();

        if (tourList.isEmpty()) {
            return null;
        }

        ArrayList<tourDTO> tourArray = new ArrayList<>();
        tourDTO tDTO;
        Object costObj = null;
        for (Escursione t : tourList) {
            tDTO = setTourDTO(t, costObj);
            tourArray.add(tDTO);
        }

        return tourArray;
    }

    @Override
    public ArrayList<TripDTO> getAllTrip() {
        List<Viaggio> tripList = eMan.createNamedQuery("Viaggio.findAll", Viaggio.class)
                .getResultList();

        if (tripList.isEmpty()) {
            return null;
        }

        TripDTO vDTO;
        Object costObj = null;

        ArrayList<TripDTO> tripArray = new ArrayList<>();
        for (Viaggio v : tripList) {
            vDTO = setTripDTO(v, costObj);
            tripArray.add(vDTO);
        }
        return tripArray;
    }

    @Override
    public ArrayList<PacchettoDTO> getAllPacketsOnsale() {

        Date today = new Date();
        List<Pacchetto> packList = eMan.createNamedQuery("Pacchetto.findByOnSaleInDate", Pacchetto.class)
                .setParameter("onSale", 1)
                .setParameter("date", today)
                .getResultList();

        if (packList.isEmpty()) {
            return null;
        }

        ArrayList<PacchettoDTO> packArray = new ArrayList<>();
        PacchettoDTO packet;
        for (Pacchetto p : packList) {
            packet = setPacchettoDTO(p);
            packArray.add(packet);
        }

        return packArray;
    }

    @Override
    public ArrayList<PacchettoDTO> getAllPackets() 
    {
        List<Pacchetto> packList = eMan.createNamedQuery("Pacchetto.findAll", Pacchetto.class)
                .getResultList();
        
        if (packList.isEmpty()) {
            return null;
        }
        ArrayList<PacchettoDTO> packArray = new ArrayList<>();
        PacchettoDTO packet;
        for (Pacchetto p : packList) {
            packet = setPacchettoDTO(p);
            packArray.add(packet);
        }

        return packArray;
    }

    @Override
    public ArrayList<PacchettoDTO> getAllPacketsWithPredicate(Date retDate, Date depDate, cittaDTO arrC, cittaDTO depC)
    {
        List<Pacchetto> packList = eMan.createNamedQuery("Pacchetto.findByPredicateDate", Pacchetto.class)
                .setParameter("dateDal", depDate)
                .setParameter("dateAl", retDate)
                .setParameter("onSale", 1)
                .getResultList();

        if (packList.isEmpty()) {
            return null;
        }
        int arrIndex = 0;
        int depIndex = 0;
        
        if(arrC!=null)
            arrIndex = arrC.getIdCity();
        
        if(depC!=null)
            depIndex = depC.getIdCity();
        
        ArrayList<PacchettoDTO> packArray = new ArrayList<>();
        PacchettoDTO packet;
        boolean taken;
        for (Pacchetto p : packList) 
        {
            taken = checkCityinPacket(p, arrIndex, depIndex);
            if(taken)
            {
                packet = setPacchettoDTO(p);
                packArray.add(packet);
            }
        } 
        
        return packArray;
    }

    private boolean checkCityinPacket(Pacchetto p, int indexArr, int indexDep)
    {
        List<Viaggio> listTrip = p.getTripBelongsTo();
        for (Viaggio v : listTrip) {
            Citta cArr = v.getFkArrivo();
            Citta cDep = v.getFkPartenza();
            if(cArr.getIdCitta()==indexArr || cDep.getIdCitta()==indexDep)
                return true;
        }
        
        return true;
    }
    
    
    
    @Override
    public ArrayList<cittaDTO> getAllCity() {
        List<Citta> cityList = eMan.createNamedQuery("Citta.findAll", Citta.class)
                .getResultList();

        if (cityList.isEmpty()) {
            return null;
        }

        ArrayList<cittaDTO> cityArray = new ArrayList<>();
        for (Citta c : cityList) {
            cityArray.add(new cittaDTO(c.getCity(), c.getCountry(), c.getIdCitta()));
        }
        return cityArray;
    }

    private cittaDTO setCityDTO(Citta c) {
        cittaDTO cDTO = new cittaDTO();
        cDTO.setCityName(c.getCity());
        cDTO.setCountryName(c.getCountry());
        cDTO.setIdCity(c.getIdCitta());
        return cDTO;
    }

    private TravelWayDTO setTwayDTO(Tipoviaggio tv) {
        TravelWayDTO twDTO = new TravelWayDTO();
        twDTO.setIdTWay(tv.getIdTipoViaggio());
        twDTO.setNameWay(tv.getName());
        return twDTO;
    }

    private PacchettoDTO setPacchettoDTO(Pacchetto p) {
        PacchettoDTO packet = new PacchettoDTO();
        packet.setDates(p.getDal(), p.getAl());
        packet.setPacchettoDTO(p.getName(), p.getDescription(), p.getPredefinito(), p.getOnSale());
        packet.setHotels(getHotelsInPacket(p));
        packet.setTours(getToursInPacket(p));
        packet.setTrip(getTravelInpacket(p));
        packet.setIdPacchetto(p.getIdPacchetto());
        packet.setRoom(setStanzaDTO(p.getFkStanza()));
        return packet;
    }

    private hotelDTO setHotelDTO(Hotel h, Object costObj) {
        hotelDTO hDTO = new hotelDTO();
        hDTO.setIdHotel(h.getIdHotel());
        hDTO.setNameHotel(h.getName());
        hDTO.setAddress(h.getAddress());
        hDTO.setDescr(h.getDescription());
        hDTO.setRating(h.getRating());
        costObj = Double.valueOf(h.getCost());
        hDTO.setCost(costObj);
        hDTO.setCityHotel(setCityDTO(h.getFkCitta()));

        return hDTO;
    }

    private TripDTO setTripDTO(Viaggio v, Object costObj) {
        TripDTO vDTO = new TripDTO();
        costObj = Double.valueOf(v.getCost());
        vDTO.setCost(costObj);
        vDTO.setCittaArr(setCityDTO(v.getFkArrivo()));
        vDTO.setCittaDep(setCityDTO(v.getFkPartenza()));
        vDTO.settWay(setTwayDTO(v.getFkTipoViaggio()));
        vDTO.setIdTrip(v.getIdViaggio());

        String travelName = v.getFkArrivo().getCity() + " " + v.getFkPartenza().getCity() + " - " + v.getFkTipoViaggio().getName();
        vDTO.setName(travelName);

        return vDTO;
    }

    private tourDTO setTourDTO(Escursione t, Object costObj) {
        tourDTO tDTO = new tourDTO();
        tDTO.setNameTour(t.getName());
        tDTO.setTourDescription(t.getDescription());
        costObj = Double.valueOf(t.getCost());
        tDTO.setCost(costObj);
        tDTO.setIdTour(t.getIdEscursioni());
        tDTO.setCity(setCityDTO(t.getFkCitta()));

        return tDTO;
    }

    private stanzaDTO setStanzaDTO(Tipostanza ts) {
        stanzaDTO sDTO = new stanzaDTO(ts.getName(), ts.getIdStanza());
        return sDTO;
    }

    private ArrayList<hotelDTO> getHotelsInPacket(Pacchetto p) {
        ArrayList<hotelDTO> hotelArray = new ArrayList<>();
        List<Hotel> hotels = p.getHotelsBelongTo();
        hotelDTO hDTO;
        Object costObj = null;
        for (Hotel h : hotels) {
            hDTO = setHotelDTO(h, costObj);
            hotelArray.add(hDTO);
        }
        return hotelArray;
    }

    private ArrayList<tourDTO> getToursInPacket(Pacchetto p) {

        ArrayList<tourDTO> tourArray = new ArrayList<>();
        List<Escursione> tour = p.getToursBelongTo();
        tourDTO tDTO;
        Object costObj = null;
        for (Escursione t : tour) {
            tDTO = setTourDTO(t, costObj);
            tourArray.add(tDTO);
        }
        return tourArray;
    }

    private ArrayList<TripDTO> getTravelInpacket(Pacchetto p) {

        ArrayList<TripDTO> travelArray = new ArrayList<>();
        List<Viaggio> travel = p.getTripBelongsTo();
        TripDTO tDTO;
        Object costObj = null;
        for (Viaggio v : travel) {
            tDTO = setTripDTO(v, costObj);
            travelArray.add(tDTO);
        }
        return travelArray;
    }

}
